/**
 * This file is Copyright © 2008 Software Craftsmen Limited. All Rights Reserved.
 */
package com.softwarecraftsmen.orogeny.filing;

import com.softwarecraftsmen.orogeny.filing.Folder.OrdinaryFolder;
import com.softwarecraftsmen.orogeny.filing.fileSystems.FileSystem;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Date;
import java.util.List;

import static com.softwarecraftsmen.orogeny.filing.Folder.isReservedFolderName;
import static java.lang.String.format;
import static java.lang.System.currentTimeMillis;
import static java.nio.file.Paths.get;
import static java.util.Locale.UK;

public class FileName
{
	private final String fileName;

	public FileName(final @NotNull String fileName)
	{
		if (fileName.isEmpty())
		{
			throw new IllegalArgumentException("fileName can not be empty");
		}
		if (isReservedFolderName(fileName))
		{
			throw new IllegalArgumentException(format(UK, "fileName %1$s is a reserved folder name", fileName));
		}
		this.fileName = fileName;
	}

	@NotNull
	public String toString()
	{
		return fileName;
	}

	public boolean equals(final @Nullable Object o)
	{
		if (this == o)
		{
			return true;
		}
		if (o == null || getClass() != o.getClass())
		{
			return false;
		}

		final FileName fileName1 = (FileName) o;
		return fileName.equals(fileName1.fileName);
	}

	public int hashCode()
	{
		return fileName.hashCode();
	}

	@NotNull
	public String toFileSystemSpecificPath(final @NotNull AbsoluteDirectory absoluteDirectory)
	{
		return absoluteDirectory.toFileSystemSpecificPath(fileName);
	}

	@NotNull
	public String toFileSystemSpecificPath(final @NotNull FileSystem fileSystem, final @NotNull RelativeDirectory relativeDirectory)
	{
		return relativeDirectory.toFileSystemSpecificPath(fileSystem, fileName);
	}

	@NotNull
	public String toFileSystemSpecificPathPrefixedByPathSeparator(final @NotNull AbsoluteDirectory absoluteDirectory)
	{
		return absoluteDirectory.toFileSystemSpecificPathPrefixedByPathSeparator(fileName);
	}

	@NotNull
	public String toFileSystemSpecificPathPrefixedByPathSeparator(final @NotNull FileSystem fileSystem, final @NotNull RelativeDirectory relativeDirectory)
	{
		return relativeDirectory.toFileSystemSpecificPathPrefixedByPathSeparator(fileSystem, fileName);
	}

	@NotNull
	public String toFileSystemSpecificPathPostfixedByPathSeparator(final @NotNull AbsoluteDirectory absoluteDirectory)
	{
		return absoluteDirectory.toFileSystemSpecificPathPostfixedByPathSeparator(fileName);
	}

	@NotNull
	public String toFileSystemSpecificPathPostfixedByPathSeparator(final @NotNull FileSystem fileSystem, final @NotNull RelativeDirectory relativeDirectory)
	{
		return relativeDirectory.toFileSystemSpecificPathPostfixedByPathSeparator(fileSystem, fileName);
	}

	@NotNull
	public File toFile(final @NotNull AbsoluteDirectory absoluteDirectory)
	{
		return new File(toFileSystemSpecificPath(absoluteDirectory));
	}

	public boolean exists(final @NotNull AbsoluteDirectory absoluteDirectory)
	{
		final String path = toFileSystemSpecificPath(absoluteDirectory);
		final Path path1 = get(path);
		return Files.isRegularFile(path1) || Files.isSymbolicLink(path1);
	}

	public boolean isHidden(final @NotNull FileSystem fileSystem, final @NotNull List<OrdinaryFolder> folders)
	{
		return fileSystem.isHidden(folders, fileName);
	}

	public void delete(final @NotNull AbsoluteDirectory absoluteDirectory) throws IsNotAFileException, CouldNotDeleteFileException
	{
		if (!exists(absoluteDirectory))
		{
			throw new IsNotAFileException(absoluteDirectory, this);
		}
		if (!exists(absoluteDirectory))
		{
			return;
		}
		final boolean deleted = toFile(absoluteDirectory).delete();
		if (!deleted)
		{
			throw new CouldNotDeleteFileException(absoluteDirectory, this);
		}
	}

	public boolean hasExtension(final @NotNull String extension)
	{
		final String dottedExtension = extension.startsWith(".") ? extension : "." + extension;
		return fileName.endsWith(dottedExtension);
	}

	@NotNull
	public FileName timestampedName()
	{
		return new FileName(format(UK, "%1$s.%2$tY.%2$tm.%2$td.%2$tH.%2$tM.%2$tS.%2$tN", fileName, new Date(currentTimeMillis())));
	}

	public void write(final @NotNull Writer writer) throws IOException
	{
		writer.write(fileName);
	}

	public void write(final @NotNull StringWriter writer)
	{
		writer.write(fileName);
	}
}
